{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 4.HTML报告"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "e:\\test notebook\\seleium\\temp\n",
      "2025-08-22-00 37 37\n",
      "<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<testbaidu1.Baidu1 testMethod=test_hao>, <testbaidu1.Baidu1 testMethod=test_hbaidu>]>]>]>\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "ok test_hao (testbaidu1.Baidu1)\n",
      "ok test_hbaidu (testbaidu1.Baidu1)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<ipykernel.iostream.OutStream object at 0x0000012D9FEEBC08> \n",
      "Time Elapsed: 0:00:29.327294\n"
     ]
    }
   ],
   "source": [
    "import HTMLTestRunner\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "import unittest\n",
    "\n",
    "def createsuite():\n",
    "\n",
    "    discovers = unittest.defaultTestLoader.discover(r\"E:\\test notebook\\seleium\\temp\\src20250820\", pattern=\"testbaidu1.py\", top_level_dir=None)\n",
    "    print(discovers)\n",
    "    return discovers\n",
    "\n",
    "if __name__==\"__main__\":\n",
    "    # 文件夹要创建在哪里\n",
    "    \n",
    "    #假设你运行的脚本路径是 /Users/ruijie/projects/test_runner/main.py，那么：\n",
    "    #sys.path[0]  # 就是 '/Users/ruijie/projects/test_runner'\n",
    "\n",
    "    curpath = sys.path[0]\n",
    "    #print(sys.path)\n",
    "    print(sys.path[0])\n",
    "    # 1，创建文件夹，\n",
    "    if not os.path.exists(curpath+'/resultreport'):\n",
    "        os.makedirs(curpath+'/resultreport')\n",
    "\n",
    "    # 2，文件夹的命名，不能让名称重复\n",
    "    # 时间  时分秒 ——》名称绝对不会重复\n",
    "    now = time.strftime(\"%Y-%m-%d-%H %M %S\", time.localtime(time.time()))\n",
    "    print(now)\n",
    "    # print(time.time())\n",
    "    # print(time.localtime(time.time()))\n",
    "    # 文件名\n",
    "    filename = curpath + '/resultreport/'+ now + 'resultreport.html'\n",
    "\n",
    "    with open(filename, 'wb') as fp:\n",
    "\n",
    "        runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=\"测试报告\",\n",
    "                                               description=\"用例执行情况\", verbosity=2)\n",
    "        suite = createsuite()\n",
    "        runner.run(suite)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "e:\\test notebook\\seleium\\temp\n",
      "2025-08-22-00 48 13\n",
      "<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<unittest.suite.TestSuite tests=[<testbaidu2.Baidu2 testMethod=test_haidusearch>, <testbaidu2.Baidu2 testMethod=test_hao>]>]>]>\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "ok test_haidusearch (testbaidu2.Baidu2)\n",
      "F  test_hao (testbaidu2.Baidu2)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<ipykernel.iostream.OutStream object at 0x000001D458D08508> \n",
      "Time Elapsed: 0:00:26.367929\n"
     ]
    }
   ],
   "source": [
    "import HTMLTestRunner\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "import unittest\n",
    "\n",
    "def createsuite():\n",
    "\n",
    "    discovers = unittest.defaultTestLoader.discover(r\"E:\\test notebook\\seleium\\temp\\src20250820\", pattern=\"testbaidu2.py\", top_level_dir=None)\n",
    "    print(discovers)\n",
    "    return discovers\n",
    "\n",
    "if __name__==\"__main__\":\n",
    "    # 文件夹要创建在哪里\n",
    "    \n",
    "    #假设你运行的脚本路径是 /Users/ruijie/projects/test_runner/main.py，那么：\n",
    "    #sys.path[0]  # 就是 '/Users/ruijie/projects/test_runner'\n",
    "\n",
    "    curpath = sys.path[0]\n",
    "    #print(sys.path)\n",
    "    print(sys.path[0])\n",
    "    # 1，创建文件夹，\n",
    "    if not os.path.exists(curpath+'/resultreport'):\n",
    "        os.makedirs(curpath+'/resultreport')\n",
    "\n",
    "    # 2，文件夹的命名，不能让名称重复\n",
    "    # 时间  时分秒 ——》名称绝对不会重复\n",
    "    now = time.strftime(\"%Y-%m-%d-%H %M %S\", time.localtime(time.time()))\n",
    "    print(now)\n",
    "    # print(time.time())\n",
    "    # print(time.localtime(time.time()))\n",
    "    # 文件名\n",
    "    filename = curpath + '/resultreport/'+ now + 'resultreport.html'\n",
    "\n",
    "    with open(filename, 'wb') as fp:\n",
    "\n",
    "        runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=\"测试报告\",\n",
    "                                               description=\"用例执行情况\", verbosity=2)\n",
    "        suite = createsuite()\n",
    "        runner.run(suite)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 5.异常捕捉和错误截图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "神雕侠侣 - 搜狗搜索\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      ".e:\\python\\lib\\unittest\\suite.py:107: ResourceWarning: unclosed file <_io.BufferedWriter name='nul'>\n",
      "  for index, test in enumerate(self):\n",
      "ResourceWarning: Enable tracemalloc to get the object allocation traceback\n",
      ".e:\\python\\lib\\unittest\\suite.py:84: ResourceWarning: unclosed file <_io.BufferedWriter name='nul'>\n",
      "  return self.run(*args, **kwds)\n",
      "ResourceWarning: Enable tracemalloc to get the object allocation traceback\n",
      "\n",
      "----------------------------------------------------------------------\n",
      "Ran 2 tests in 30.566s\n",
      "\n",
      "OK\n"
     ]
    }
   ],
   "source": [
    "from selenium import webdriver\n",
    "import unittest\n",
    "import time\n",
    "import os\n",
    "from selenium.webdriver.common.by import By  # 需导入By类\n",
    "from selenium.webdriver.chrome.service import Service\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "\n",
    "\n",
    "class Baidu1(unittest.TestCase):\n",
    "\n",
    "    def setUp(self):\n",
    "        # 指定 ChromeDriver 和 Chrome 浏览器路径\n",
    "        chrome_driver_path = \"F:/Google Chrome/chromedriver-win64/chromedriver.exe\"\n",
    "        chrome_binary_path = \"F:/Google Chrome/Google/Chrome/Application/chrome.exe\"\n",
    "\n",
    "        # 配置 Chrome 启动选项\n",
    "        options = Options()\n",
    "        options.binary_location = chrome_binary_path\n",
    "\n",
    "        # 创建服务对象并启动浏览器\n",
    "        service = Service(executable_path=chrome_driver_path)      \n",
    "        self.driver = webdriver.Chrome(service=service, options=options)       \n",
    "        self.driver.implicitly_wait(30)\n",
    "        self.base_url = \"https://www.sogou.com/\"\n",
    "        self.verificationErrors=[]\n",
    "        \n",
    "\n",
    "    def tearDown(self):\n",
    "        self.driver.quit()\n",
    "        self.assertEqual([],self.verificationErrors)\n",
    "\n",
    "      # 忽略此测试用例\n",
    "    #@unittest.skip(\"skipping\")\n",
    "    def test_baidusearch(self):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.find_element(By.ID, \"query\").clear() \n",
    "        driver.find_element(By.ID, \"query\").send_keys(\"向往的生活\")  \n",
    "        driver.find_element(By.ID, \"stb\").click()\n",
    "        time.sleep(2)\n",
    "\n",
    "\n",
    "    def test_baidu(self):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.maximize_window()\n",
    "        driver.find_element(By.ID, \"query\").clear()  # 清除输入框内容\n",
    "        driver.find_element(By.ID, \"query\").send_keys(\"神雕侠侣\")\n",
    "        driver.find_element(By.ID, \"stb\").click()  # 点击搜索按钮\n",
    "        time.sleep(3)\n",
    "        print(driver.title)\n",
    "        try:\n",
    "            self.assertEqual(driver.title, u\"百度一下，你就知道\", msg=\"不相等\")\n",
    "        except:\n",
    "            self.saveScreenShot(driver, \"sdxl.png\")   # 出现异常就调用截图函数进行截图\n",
    "        time.sleep(3)\n",
    "\n",
    "    # 截图函数\n",
    "    def saveScreenShot(self, driver, file_name):\n",
    "        # 统一使用绝对路径\n",
    "        image_dir = \"E:/test notebook/seleium/temp/src20250820/image\"\n",
    "        if not os.path.exists(image_dir):\n",
    "            os.makedirs(image_dir)\n",
    "\n",
    "        now = time.strftime(\"%Y%m%d-%H%M%S\", time.localtime(time.time()))\n",
    "        full_path = os.path.join(image_dir, f\"{now}-{file_name}\")\n",
    "        driver.get_screenshot_as_file(full_path)\n",
    "        time.sleep(3)\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    unittest.main(argv=['first-arg-is-ignored'], exit=False) #避免解析 Jupyter 的参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 6.数据驱动DDT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 6.1一次性单个参数和一次性多个参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "倚天屠龙记 - 搜狗搜索\n",
      "倚天屠龙记 - 搜狗搜索\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "射雕英雄传 - 搜狗搜索\n",
      "射雕英雄传 - 搜狗搜索\n"
     ]
    }
   ],
   "source": [
    "from selenium import webdriver\n",
    "import unittest\n",
    "import time\n",
    "from ddt import ddt, unpack, data, file_data\n",
    "import sys, csv\n",
    "from selenium.webdriver.common.by import By  # 需导入By类\n",
    "from selenium.webdriver.chrome.service import Service\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "\n",
    "\n",
    "\n",
    "@ddt   #在类上面要使用标签@ddt修饰\n",
    "class Baidu1(unittest.TestCase):\n",
    "    def setUp(self):\n",
    "        # 指定 ChromeDriver 和 Chrome 浏览器路径\n",
    "        chrome_driver_path = \"F:/Google Chrome/chromedriver-win64/chromedriver.exe\"\n",
    "        chrome_binary_path = \"F:/Google Chrome/Google/Chrome/Application/chrome.exe\"\n",
    "\n",
    "        # 配置 Chrome 启动选项\n",
    "        options = Options()\n",
    "        options.binary_location = chrome_binary_path\n",
    "\n",
    "        # 创建服务对象并启动浏览器\n",
    "        service = Service(executable_path=chrome_driver_path)      \n",
    "        self.driver = webdriver.Chrome(service=service, options=options)\n",
    "        \n",
    "        self.driver.implicitly_wait(10)\n",
    "        self.base_url = \"https://www.sogou.com/\"\n",
    "        self.driver.maximize_window()\n",
    "        \n",
    "        \n",
    "    def tearDown(self):\n",
    "        self.driver.quit()\n",
    "        \n",
    "\n",
    "    @data(\"王凯\", \"Lisa\", \"特朗普\", \"李沁\")\n",
    "    def test_baidu1(self, value):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.maximize_window()\n",
    "        driver.find_element(By.ID, \"query\").clear()\n",
    "        driver.find_element(By.ID, \"query\").send_keys(value)\n",
    "        driver.find_element(By.ID, \"stb\").click()       \n",
    "        time.sleep(3)\n",
    "\n",
    "\n",
    "    \n",
    "    @data([\"倚天屠龙记\", \"倚天屠龙记 - 搜狗搜索\"], [\"射雕英雄传\", \"射雕英雄传 - 搜狗搜索\"])\n",
    "    @unpack\n",
    "    def test_baidu2(self, value, expected_value):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.find_element(By.ID, \"query\").clear()\n",
    "        driver.find_element(By.ID, \"query\").send_keys(value)\n",
    "        driver.find_element(By.ID, \"stb\").click()\n",
    "        driver.maximize_window()\n",
    "        time.sleep(6)\n",
    "        #判断搜索网页的title和我们期望的是否一致\n",
    "        self.assertEqual(expected_value, driver.title, msg=\"和预期搜索结果不一致！\")\n",
    "        print(expected_value)\n",
    "        print(driver.title)\n",
    "        time.sleep(3)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    unittest.main(argv=['first-arg-is-ignored'], exit=False) #避免解析 Jupyter 的参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 6.2 txt文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "射雕英雄传 - 搜狗搜索\n",
      "射雕英雄传 - 搜狗搜索\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      ".e:\\python\\lib\\unittest\\suite.py:107: ResourceWarning: unclosed file <_io.BufferedWriter name='nul'>\n",
      "  for index, test in enumerate(self):\n",
      "ResourceWarning: Enable tracemalloc to get the object allocation traceback\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "神雕侠侣 - 搜狗搜索\n",
      "神雕侠侣 - 搜狗搜索\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "."
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "倚天屠龙记 - 搜狗搜索\n",
      "倚天屠龙记 - 搜狗搜索\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      ".F\n",
      "======================================================================\n",
      "FAIL: test_baidu2_4___赛博朋克____倚天屠龙记___搜狗搜索__ (__main__.Baidu1)\n",
      "----------------------------------------------------------------------\n",
      "Traceback (most recent call last):\n",
      "  File \"e:\\python\\lib\\site-packages\\ddt.py\", line 221, in wrapper\n",
      "    return func(self, *args, **kwargs)\n",
      "  File \"C:\\Users\\12525\\AppData\\Local\\Temp\\ipykernel_142536\\217290181.py\", line 62, in test_baidu2\n",
      "    self.assertEqual(expected_value, driver.title, msg=\"和预期搜索结果不一致！\")\n",
      "AssertionError: '倚天屠龙记 - 搜狗搜索' != '赛博朋克 - 搜狗搜索'\n",
      "- 倚天屠龙记 - 搜狗搜索\n",
      "+ 赛博朋克 - 搜狗搜索\n",
      " : 和预期搜索结果不一致！\n",
      "\n",
      "----------------------------------------------------------------------\n",
      "Ran 4 tests in 54.524s\n",
      "\n",
      "FAILED (failures=1)\n"
     ]
    }
   ],
   "source": [
    "from selenium import webdriver\n",
    "import unittest\n",
    "import time\n",
    "from ddt import ddt, unpack, data, file_data\n",
    "import sys, csv\n",
    "from selenium.webdriver.common.by import By  # 需导入By类\n",
    "from selenium.webdriver.chrome.service import Service\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "\n",
    "def getTxt(file_name):\n",
    "    # [[周迅,周迅_百度搜索],[张国荣,张国荣_百度搜索],[张一山，张一山_百度搜索]]\n",
    "    rows = []\n",
    "    path = sys.path[0]\n",
    "    with open(path + '/src20250820/data/' + file_name, 'r', encoding='utf-8') as f:\n",
    "        readers = csv.reader(f, delimiter=',', quotechar='|')\n",
    "        next(readers, None)  # 跳过第一行（通常是表头）\n",
    "        for row in readers:\n",
    "            temprows=[]\n",
    "            for i in row:\n",
    "                # 周迅,周迅_百度搜索\n",
    "                temprows.append(i)\n",
    "            rows.append(temprows)\n",
    "        return rows\n",
    "\n",
    "@ddt   #在类上面要使用标签@ddt修饰\n",
    "class Baidu1(unittest.TestCase):\n",
    "    def setUp(self):\n",
    "        # 指定 ChromeDriver 和 Chrome 浏览器路径\n",
    "        chrome_driver_path = \"F:/Google Chrome/chromedriver-win64/chromedriver.exe\"\n",
    "        chrome_binary_path = \"F:/Google Chrome/Google/Chrome/Application/chrome.exe\"\n",
    "\n",
    "        # 配置 Chrome 启动选项\n",
    "        options = Options()\n",
    "        options.binary_location = chrome_binary_path\n",
    "\n",
    "        # 创建服务对象并启动浏览器\n",
    "        service = Service(executable_path=chrome_driver_path)      \n",
    "        self.driver = webdriver.Chrome(service=service, options=options)\n",
    "        \n",
    "        self.driver.implicitly_wait(10)\n",
    "        self.base_url = \"https://www.sogou.com/\"\n",
    "        self.driver.maximize_window()\n",
    "        \n",
    "        \n",
    "    def tearDown(self):\n",
    "        self.driver.quit()\n",
    "        \n",
    "    \n",
    "    @data(*getTxt('sougou.txt'))\n",
    "    \n",
    "    # @data([\"倚天屠龙记\", \"倚天屠龙记 - 搜狗搜索\"], [\"射雕英雄传\", \"射雕英雄传 - 搜狗搜索\"])\n",
    "    @unpack\n",
    "    def test_baidu2(self, value, expected_value):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.find_element(By.ID, \"query\").clear()\n",
    "        driver.find_element(By.ID, \"query\").send_keys(value)\n",
    "        driver.find_element(By.ID, \"stb\").click()\n",
    "        driver.maximize_window()\n",
    "        time.sleep(3)\n",
    "        #判断搜索网页的title和我们期望的是否一致\n",
    "        self.assertEqual(expected_value, driver.title, msg=\"和预期搜索结果不一致！\")\n",
    "        print(expected_value)\n",
    "        print(driver.title)\n",
    "        time.sleep(2)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    unittest.main(argv=['first-arg-is-ignored'], exit=False) #避免解析 Jupyter 的参数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 6.3 json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
     
      "Ran 3 tests in 34.063s\n",
      "OK\n"
     ]
    }
   ],
   "source": [
    "from selenium import webdriver\n",
    "import unittest\n",
    "import time\n",
    "from ddt import ddt, unpack, data, file_data\n",
    "import sys, csv\n",
    "from selenium.webdriver.common.by import By  # 需导入By类\n",
    "from selenium.webdriver.chrome.service import Service\n",
    "from selenium.webdriver.chrome.options import Options\n",
    "import os\n",
    "import json\n",
    "\n",
    "#Jupyter Notebook 用 @file_data 有问题，没办法替换一下，.py文件可以直接用\n",
    "def load_json_data(file_path):\n",
    "    with open(file_path, 'r', encoding='utf-8') as f:\n",
    "        return json.load(f)\n",
    "    \n",
    "\n",
    "@ddt   #在类上面要使用标签@ddt修饰\n",
    "class Baidu1(unittest.TestCase):\n",
    "    test_data = load_json_data(\"E:/test notebook/seleium/temp/src20250820/data/sougou.json\")\n",
    "\n",
    "    def setUp(self):\n",
    "        # 指定 ChromeDriver 和 Chrome 浏览器路径\n",
    "        chrome_driver_path = \"F:/Google Chrome/chromedriver-win64/chromedriver.exe\"\n",
    "        chrome_binary_path = \"F:/Google Chrome/Google/Chrome/Application/chrome.exe\"\n",
    "\n",
    "        # 配置 Chrome 启动选项\n",
    "        options = Options()\n",
    "        options.binary_location = chrome_binary_path\n",
    "\n",
    "        # 创建服务对象并启动浏览器\n",
    "        service = Service(executable_path=chrome_driver_path)      \n",
    "        self.driver = webdriver.Chrome(service=service, options=options)\n",
    "        \n",
    "        self.driver.implicitly_wait(10)\n",
    "        self.base_url = \"https://www.sogou.com/\"\n",
    "        self.driver.maximize_window()\n",
    "        \n",
    "        \n",
    "        \n",
    "    def tearDown(self):\n",
    "        self.driver.quit()\n",
    "        \n",
    "    @data(*test_data)\n",
    "    #@file_data('sougou.json')\n",
    " \n",
    "    # @data(\"王凯\", \"Lisa\", \"特朗普\", \"李沁\")\n",
    "    def test_baidu1(self, value):\n",
    "        driver = self.driver\n",
    "        driver.get(self.base_url)\n",
    "        driver.maximize_window()\n",
    "        driver.find_element(By.ID, \"query\").clear()\n",
    "        driver.find_element(By.ID, \"query\").send_keys(value)\n",
    "        driver.find_element(By.ID, \"stb\").click()\n",
    "        \n",
    "        time.sleep(3)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    unittest.main(argv=['first-arg-is-ignored'], exit=False) #避免解析 Jupyter 的参数"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
